(function($) {
	$.fn
			.extend({
				complexify : function(options, callback) {
					var MIN_COMPLEXITY = 49;
					var MAX_COMPLEXITY = 120;
					var CHARSETS = [ [ 0x0030, 0x0039 ], [ 0x0041, 0x005A ],
							[ 0x0061, 0x007A ], [ 0x0021, 0x002F ],
							[ 0x003A, 0x0040 ], [ 0x005B, 0x0060 ],
							[ 0x007B, 0x007E ], [ 0x0080, 0x00FF ],
							[ 0x0100, 0x017F ], [ 0x0180, 0x024F ],
							[ 0x0250, 0x02AF ], [ 0x02B0, 0x02FF ],
							[ 0x0300, 0x036F ], [ 0x0370, 0x03FF ],
							[ 0x0400, 0x04FF ], [ 0x0530, 0x058F ],
							[ 0x0590, 0x05FF ], [ 0x0600, 0x06FF ],
							[ 0x0700, 0x074F ], [ 0x0780, 0x07BF ],
							[ 0x0900, 0x097F ], [ 0x0980, 0x09FF ],
							[ 0x0A00, 0x0A7F ], [ 0x0A80, 0x0AFF ],
							[ 0x0B00, 0x0B7F ], [ 0x0B80, 0x0BFF ],
							[ 0x0C00, 0x0C7F ], [ 0x0C80, 0x0CFF ],
							[ 0x0D00, 0x0D7F ], [ 0x0D80, 0x0DFF ],
							[ 0x0E00, 0x0E7F ], [ 0x0E80, 0x0EFF ],
							[ 0x0F00, 0x0FFF ], [ 0x1000, 0x109F ],
							[ 0x10A0, 0x10FF ], [ 0x1100, 0x11FF ],
							[ 0x1200, 0x137F ], [ 0x13A0, 0x13FF ],
							[ 0x1400, 0x167F ], [ 0x1680, 0x169F ],
							[ 0x16A0, 0x16FF ], [ 0x1780, 0x17FF ],
							[ 0x1800, 0x18AF ], [ 0x1E00, 0x1EFF ],
							[ 0x1F00, 0x1FFF ], [ 0x2000, 0x206F ],
							[ 0x2070, 0x209F ], [ 0x20A0, 0x20CF ],
							[ 0x20D0, 0x20FF ], [ 0x2100, 0x214F ],
							[ 0x2150, 0x218F ], [ 0x2190, 0x21FF ],
							[ 0x2200, 0x22FF ], [ 0x2300, 0x23FF ],
							[ 0x2400, 0x243F ], [ 0x2440, 0x245F ],
							[ 0x2460, 0x24FF ], [ 0x2500, 0x257F ],
							[ 0x2580, 0x259F ], [ 0x25A0, 0x25FF ],
							[ 0x2600, 0x26FF ], [ 0x2700, 0x27BF ],
							[ 0x2800, 0x28FF ], [ 0x2E80, 0x2EFF ],
							[ 0x2F00, 0x2FDF ], [ 0x2FF0, 0x2FFF ],
							[ 0x3000, 0x303F ], [ 0x3040, 0x309F ],
							[ 0x30A0, 0x30FF ], [ 0x3100, 0x312F ],
							[ 0x3130, 0x318F ], [ 0x3190, 0x319F ],
							[ 0x31A0, 0x31BF ], [ 0x3200, 0x32FF ],
							[ 0x3300, 0x33FF ], [ 0x3400, 0x4DB5 ],
							[ 0x4E00, 0x9FFF ], [ 0xA000, 0xA48F ],
							[ 0xA490, 0xA4CF ], [ 0xAC00, 0xD7A3 ],
							[ 0xD800, 0xDB7F ], [ 0xDB80, 0xDBFF ],
							[ 0xDC00, 0xDFFF ], [ 0xE000, 0xF8FF ],
							[ 0xF900, 0xFAFF ], [ 0xFB00, 0xFB4F ],
							[ 0xFB50, 0xFDFF ], [ 0xFE20, 0xFE2F ],
							[ 0xFE30, 0xFE4F ], [ 0xFE50, 0xFE6F ],
							[ 0xFE70, 0xFEFE ], [ 0xFEFF, 0xFEFF ],
							[ 0xFF00, 0xFFEF ], [ 0xFFF0, 0xFFFD ] ];
					var defaults = {
						minimumChars : 8,
						strengthScaleFactor : 1
					};
					if ($.isFunction(options) && !callback) {
						callback = options;
						options = {};
					}
					options = $.extend(defaults, options);
					function additionalComplexityForCharset(str, charset) {
						for (var i = str.length - 1; i >= 0; i--) {
							if (charset[0] <= str.charCodeAt(i)
									&& str.charCodeAt(i) <= charset[1]) {
								return charset[1] - charset[0] + 1;
							}
							;
						}
						;
						return 0;
					}
					;
					return this
							.each(function() {
								$(this)
										.keyup(
												function() {
													var password = $(this)
															.val();
													var complexity = 0, valid = false;
													for (var i = CHARSETS.length - 1; i >= 0; i--) {
														complexity += additionalComplexityForCharset(
																password,
																CHARSETS[i]);
													}
													complexity = Math
															.log(Math
																	.pow(
																			complexity,
																			password.length))
															* (1 / options.strengthScaleFactor);
													valid = (complexity > MIN_COMPLEXITY && password.length >= options.minimumChars);
													complexity = (complexity / MAX_COMPLEXITY) * 100;
													complexity = (complexity > 100) ? 100
															: complexity;
													callback.call(this, valid,
															complexity);
												});
							});
				}
			});
})(jQuery);